package teamproject.graphEditor;

import java.util.Collection;

import edu.uci.ics.jung.graph.DirectedGraph;
import edu.uci.ics.jung.graph.DirectedSparseGraph;
import edu.uci.ics.jung.graph.util.Pair;

/**
 * Contains static methods for graph operations
 * 
 */
public class GraphUtils {

	/**
	 * Returns a deep Copy of specified directed Graph
	 * 
	 * @param g
	 *            the directed graph which should be copied
	 * @param control
	 *            the Controller which contains edge and node factories
	 * @return a deep copy of a directed graph
	 */
	@SuppressWarnings("static-access")
	public static DirectedGraph<Node, PDEEdge> deepCopy(
			DirectedGraph<Node, PDEEdge> g, Controller control) {
		DirectedGraph<Node, PDEEdge> copy = new DirectedSparseGraph<Node, PDEEdge>();
		Object[] nodes = g.getVertices().toArray();
		Object[] edges = g.getEdges().toArray();
		// SaveGraph sg = new SaveGraph(g);
		// ArrayList<Node> sortedNodes = sg.sortNodes(g.getVertices());
		// ArrayList<PDEEdge> sortedEdges = sg.sortNodes(g.getVertices());
		NodeFactory factory = new NodeFactory().instance2;
		factory.clear();
		factory.setNodes(copy.getVertices());
		// Kopiere KnotenNamen
		for (int i = 0; i < nodes.length; i++) {
			Node toBeAdded = factory.create();
			for (int j = 0; j < nodes.length; j++) {
				if (((Integer) toBeAdded.getId()).equals(((Node) nodes[j])
						.getId())) {
					toBeAdded.setName(((Node) nodes[j]).getName());

				}
			}
			copy.addVertex(toBeAdded);
		}
		Object[] copiedNodes = copy.getVertices().toArray();

		// initialisieren der edgeFactory
		PDEEdgeFactory edgeFactory = new PDEEdgeFactory().instance2;
		edgeFactory.clear();
		edgeFactory.setEdgeAttributeNames(control.getEdgeFactory()
				.getEdgeAttributeNames());
		edgeFactory.setEdgeValues(control.getEdgeFactory().getEdgeValues());
		// Kopiere Kanten

		for (int i = 0; i < edges.length; i++) {
			Pair<Node> endpoints = g.getEndpoints((PDEEdge) edges[i]);

			// kopiere Kante
			PDEEdge tmp = (PDEEdge) edges[i];
			PDEEdge toBeAdded = edgeFactory.create();

			for (int j = 0; j < tmp.getAttributeNames().size(); j++) {
				toBeAdded.setAtrributeValue(j, tmp.getAtrributeValue(j));
				toBeAdded.setName(tmp.getName());
			}
			// ende kopiere Kante

			for (int j = 0; j < copiedNodes.length; j++) {
				Node erster = (Node) copiedNodes[j];

				if (endpoints.getFirst().getId() == erster.getId()) {
					for (int k = 0; k < copiedNodes.length; k++) {
						Node zweiter = (Node) copiedNodes[k];
						if (endpoints.getSecond().getId() == zweiter.getId()) {
							toBeAdded.setDestNode(zweiter.getId());

							copy.addEdge(toBeAdded, erster, zweiter);
							// copy.findEdge(erster, zweiter).setName(
							// g.findEdge(copiedStart, copiedEnd)
							// .getName());

							break;
						}
					}
				}
			}
		}
		return copy;
	}

	/**
	 * Performs a depth-first-search
	 * 
	 * @param g
	 *            the graph
	 * @param start
	 *            the start node
	 */
	public static void depthFirstSearch(DirectedGraph<Node, PDEEdge> g,
			Node start) {
		if (!g.containsVertex(start))
			throw new IllegalArgumentException("The specified node: "
					+ start.toString() + " is not part of the graph: "
					+ g.toString());

		start.setVisited(true);
		Collection<Node> neighbours = g.getNeighbors(start);
		for (Node n : neighbours) {
			if (!n.hasBeenVisited())
				depthFirstSearch(g, n);
		}
	}
}
